package com.semidata.rtd.core.http.server;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpContent;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.handler.codec.http.LastHttpContent;

import com.semidata.rtd.core.log.Logger;

public class HttpRequestHandler extends SimpleChannelInboundHandler<Object> {
	private HttpDispatchHandler handler;
	private HttpDispatcher dispatcher;
	private HttpRequest request;

	public HttpRequestHandler(HttpDispatcher dispatcher) {
		this.dispatcher = dispatcher;
	}

	@Override
	public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
		ctx.flush();
		super.channelReadComplete(ctx);
	}

	@Override
	protected void channelRead0(ChannelHandlerContext ctx, Object msg) {
		if (msg instanceof HttpRequest) {
			request = (HttpRequest) msg;
			try {
				handler = dispatcher.getDispatchHandler(ctx, request);
				if (handler == null)
					throw new NullPointerException();
			} catch (Exception e) {

				Logger.log("ERROR", e);
				HttpResponse response = new HttpResponse(ctx, request);
				response.error(HttpResponseStatus.NOT_FOUND);
				return;
			}

			if (HttpHeaders.is100ContinueExpected(request)) {
				FullHttpResponse response = new DefaultFullHttpResponse(
				        HttpVersion.HTTP_1_1, HttpResponseStatus.CONTINUE);
				ctx.write(response);
			}
		}

		if (msg instanceof HttpContent) {
			HttpContent httpContent = (HttpContent) msg;

			ByteBuf content = httpContent.content();
			if (content.isReadable()) {
				try {
					handler.handleData(content);
				} catch (Exception e) {
					Logger.log("ERROR", e.getMessage());
					HttpResponse response = new HttpResponse(ctx, request);
					response.error(HttpResponseStatus.BAD_REQUEST);
					return;
				}
			}

			if (msg instanceof LastHttpContent) {
				try {
					handler.complete();
				} catch (Exception e) {
					Logger.log("ERROR", e.getMessage());
					HttpResponse response = new HttpResponse(ctx, request);
					response.error(HttpResponseStatus.BAD_REQUEST);
					return;
				}
			}
		}
	}

	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
	        throws Exception {
		Logger.log("ERROR", cause.getMessage());
		ctx.close();
	}

}